<script setup lang="ts" name="GoodsSku">
import { GoodsInfo, Spec, SpecValue } from '@/types/goods'
import bwPowerSet from '@/utils/power-set'

// const res = bwPowerSet(['黑色', '日本', '30cm'])
// console.log('可能出现的路径集合', res)

const props = defineProps<{
  goods: GoodsInfo
  skuId?: string // 传了就默认回显高亮某些选项, 没传就不高亮 自己选
}>()

const emit = defineEmits<{
  (e: 'changeSku', value: string): void
}>()

const SPLIT_STR = '+'

// 需求: 点谁谁亮
// 0. 如果禁用了, 什么都不做
// 1. 判断当前项是否高亮, 如果高亮了, 取消高亮
// 2. 如果当前项没有高亮, 高亮当前项且排他(该规格内的)
const changeSelected = (item: Spec, sub: SpecValue) => {
  if (sub.disabled) return

  if (sub.selected) {
    sub.selected = false
  } else {
    item.values.forEach((v) => (v.selected = false))

    sub.selected = true
  }

  // console.log('选中项数组:', getSelectedSpec()) // 临时在这里先触发一下(最后)
  // 应该是点击了某个选项后, 更新禁用状态
  updateDisabledStatus()

  // 获取用户的选中项, 如果选满了, 应该子传父 告知父组件
  // console.log('选中了...', getSelectedSpec())
  const res = getSelectedSpec().filter((v) => v)
  // console.log(res)
  if (res.length === props.goods.specs.length) {
    // console.log('满了', res)
    const key = res.join(SPLIT_STR)
    const [skuId] = pathMap[key]
    // console.log(skuId) 子传父
    emit('changeSku', skuId)
  }
}

// 1. filter 筛选有效sku
// 2. map 得到每一个sku的选项数组['蓝色', '中国', '10' ]   将来需要交给bwPowerSet 得到所有的路径集合
// 3. 转化得到路径字典对象(键: 黑色+中国;  值: [skuId])
// 封装一个方法  得到路径字典

// const obj: {
//   name: string
//   age: number
// } = {
//   name: 'zs',
//   age: 19,
// }

const getPathMap = () => {
  // pathMap类型临时为any
  // pathMap键名是不确定的, 键名的类型是确定的!! 一定是字符串类型
  // 值是确定的类型 string[]
  const pathMap: {
    [key: string]: string[]
  } = {}

  // console.log(props.goods.skus)
  // 1.过滤得到有效的sku
  const validSkus = props.goods.skus.filter((item) => item.inventory > 0)
  // console.log(validSkus)

  validSkus.forEach((sku) => {
    // console.log(sku.specs) // 获取每一个有效sku的具体筛选条件
    // 想要获取具体筛选条件的路径集合 ['红色', '中国'] => ['红色'], ['中国'] ['红色', '中国']
    // 所以, 要对具体筛选条件数组 进行转换 ['蓝色', '20cm', '中国']
    const arr = sku.specs.map((item) => item.valueName)
    // console.log(arr)
    const resArr = bwPowerSet(arr)
    // console.log(resArr)

    resArr.forEach((v) => {
      // console.log(v.join('+'))
      const key = v.join(SPLIT_STR)
      // console.log(key, sku.id)
      if (key in pathMap) {
        // 键在对象中存在
        pathMap[key].push(sku.id)
      } else {
        // 键在对象中不存在的 => 新开一个属性, 值是数组 [skuId]
        pathMap[key] = [sku.id]
      }
    })
  })

  return pathMap
}

const pathMap = getPathMap()
console.log('路径字典:', pathMap)

// 封装一个方法 获取选中的选项  约定: 和specs规格数组 保持长度一致, 顺序一致, 方便查找路径字典
const getSelectedSpec = () => {
  const arr: string[] = []

  // 遍历每一个规格, 找到这个规格下的选中项
  props.goods.specs.forEach((item) => {
    const temp = item.values.find((sub) => sub.selected === true)
    // 如果找到了, push选项名字; 反之 push ''
    arr.push(temp ? temp.name : '')
  })

  return arr
}

// 封装一个方法 初始化/点击后 选项的禁用状态
const updateDisabledStatus = () => {
  // 先获取选中项数组 ['', '', '日本'], 然后和每一个选项组成一个筛选条件, 去路径字典中查找
  const selectedArr = getSelectedSpec()
  // console.log(selectedArr)

  // 遍历每一个选项 查找这个选项的name在路径字典中是否存在, 存在 disabled false; 反之 为true
  props.goods.specs.forEach((item, index) => {
    item.values.forEach((sub) => {
      // 需要将每一个选项和已经确定的筛选条件做组合['', '', '日本']!!!!!!!!!!!
      // 拷贝一下
      const tempArr = [...selectedArr]
      tempArr[index] = sub.name // ['黑色', '', '日本']
      // console.log(tempArr)
      // console.log(tempArr.filter((v) => v).join(SPLIT_STR))
      const key = tempArr.filter((v) => v).join(SPLIT_STR)
      // console.log(key)

      // console.log(sub)
      if (key in pathMap) {
        // 有货 => 可选 => false
        sub.disabled = false
      } else {
        // 没货 => 禁用
        sub.disabled = true
      }
    })
  })
}

// 封装方法 进行skuId的高亮回显
const initSelectedSpec = () => {
  if (!props.skuId) return
  // console.log(props.goods, props.skuId)
  const sku = props.goods.skus.find((item) => item.id === props.skuId)
  // console.log(sku.specs)
  if (sku) {
    // console.log(sku.specs)
    props.goods.specs.forEach((item, index) => {
      // item.values.find()
      // 获取具体筛选条件
      // console.log(sku.specs[index].valueName, 1111)
      const temp = sku.specs[index].valueName // '黑色'
      // 选项中查找对应名字的项, 让他的selected为true
      const res = item.values.find((item) => item.name === temp) // {name: '黑色', ....}
      res!.selected = true
    })
  }
}

initSelectedSpec()
updateDisabledStatus()

// bug: 珐琅锅商品页面下, 点击二级分类, 这个时候再点返回, 珐琅锅的默认禁用没了???
// 分析: updateDisabledStatus 组件创建时 触发一次 ==>> 没有清空数据!!!
</script>

<template>
  <div class="goods-sku">
    <!-- 一个规格就是一个dl -->
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <!-- v-for 和 v-if 都要用 -->
        <template v-for="sub in item.values" :key="sub.name">
          <img
            :class="{ selected: sub.selected, disabled: sub.disabled }"
            @click="changeSelected(item, sub)"
            v-if="sub.picture"
            :src="sub.picture"
            alt=""
          />
          <span
            @click="changeSelected(item, sub)"
            :class="{ selected: sub.selected, disabled: sub.disabled }"
            v-else
            >{{ sub.name }}</span
          >
        </template>
      </dd>
    </dl>
  </div>
</template>

<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 30px;
        padding: 0 20px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
